#include "Emulator.h"
#include "Log.h"
#include "pch.h"
#include <string>
#include <sstream>
#include <iostream>

// 帮助文档, consider convert to Chinese
void showUsage()
{
#ifdef CHINESE_VERSION
    std::cout << HelperProjectName << "是一个简单的NES仿真器\n"
              << "它可以运行.NES镜像\n"
              << "使用keybind.conf设置键绑定\n\n"
              << "用法:" << HelperProjectName << " [options] rom-path\n\n"
              << "Options:\n"
              << "-h, --help             打印此帮助文本并退出\n"
              << "-s, --scale            设置视频比例。默认值:3\n"
              << "                       比例为1对应于 " << PROJECT_NAME::NESVideoWidth << "x" << PROJECT_NAME::NESVideoHeight << std::endl
              << "-w, --width            设置仿真屏幕的宽度(高度为\n"
              << "                       自动设定以适合长宽比)\n"
              << "-H, --height           设置仿真屏幕的高度(宽度为\n"
              << "                       自动设定以适合长宽比)\n"
              << "                       此选项与--width互斥\n"
              << std::endl;
#endif // CHINESE_VERSION

#ifdef ENGLISH_VERSION
    std::cout << HelperProjectName << " is a simple nes emulcator.\n"
              << "It can run off .nes images.\n"
              << "Set keybindings with keybindings.conf\n\n"
              << "Usage: PNE [options] rom-path\n\n"
              << "Options:\n"
              << "-h, --help             Print this help text and exit\n"
              << "-s, --scale            Set video scale. Default: 3.\n"
              << "                       Scale of 1 corresponds to " << PROJECT_NAME::NESVideoWidth << "x" << PROJECT_NAME::NESVideoHeight << std::endl
              << "-w, --width            Set the width of the emulation screen (height is\n"
              << "                       set automatically to fit the aspect ratio)\n"
              << "-H, --height           Set the height of the emulation screen (width is\n"
              << "                       set automatically to fit the aspect ratio)\n"
              << "                       This option is mutually exclusive to --width\n"
              << std::endl;
#endif // ENGLISH_VERSION

#ifdef _WIN32
    system("pause");
#endif
}

PNE_NAMESPACE_BEGIN
void ParseControllerConf(std::string filepath, std::vector<sf::Keyboard::Key> &p1,
                         std::vector<sf::Keyboard::Key> &p2);
PNE_NAMESPACE_END // namepsace PROJECT_NAME

    int
    main(int argc, char const *argv[])
{
    // first show usage for debug
    showUsage();

    std::ofstream logFile("pne-log/pne.log"), cpuTraceFile;
    PROJECT_NAME::TeeStream logTee(logFile, std::cout);

    if (logFile.is_open() && logFile.good())
        PROJECT_NAME::Log::GetInstance().SetLogStream(logTee);
    else
        PROJECT_NAME::Log::GetInstance().SetLogStream(std::cout);

    PROJECT_NAME::Log::GetInstance().SetLevel(PROJECT_NAME::Level::Info);

    std::string path;
    //Default keybindings
    std::vector<sf::Keyboard::Key> p1 {sf::Keyboard::J, sf::Keyboard::K, sf::Keyboard::RShift, sf::Keyboard::Return,
                                       sf::Keyboard::W, sf::Keyboard::S, sf::Keyboard::A, sf::Keyboard::D},
                                   p2 {sf::Keyboard::Numpad5, sf::Keyboard::Numpad6, sf::Keyboard::Numpad8, sf::Keyboard::Numpad9,
                                       sf::Keyboard::Up, sf::Keyboard::Down, sf::Keyboard::Left, sf::Keyboard::Right};

    PROJECT_NAME::Emulator emulator;
    // 参数解释
    for (int i{1}; i < argc; ++i)
    {
        std::string arg(argv[i]);

        if (arg == "-h" || arg == "--help")
        {
            showUsage();

            return 0;
        }
        else if (std::strcmp(argv[1], "--log-cpu") == 0)
        {
            PROJECT_NAME::Log::GetInstance().SetLevel(PROJECT_NAME::Level::CpuTrace);
            // write as file pne-log/pne.cpudump ?
            cpuTraceFile.open("pne-log/pne.cpudump");
            PROJECT_NAME::Log::GetInstance().SetCpuTraceStream(cpuTraceFile);
            LOG(PROJECT_NAME::Level::Info) << "CPU logging set." << std::endl;
        }
        else if (std::strcmp(argv[i], "-s") == 0 || std::strcmp(argv[i], "--scale") == 0)
        {
            float scale;
            std::stringstream ss;
            if (i + 1 < argc && ss << argv[i + 1] && ss >> scale)
                emulator.SetVideoScale(scale);
            else
                LOG(PROJECT_NAME::Level::Error) << "Setting scale from argument failed" << std::endl;
            ++i;
        }
        else if (std::strcmp(argv[i], "-w") == 0 || std::strcmp(argv[i], "--width") == 0)
        {
            int width;
            std::stringstream ss;
            if (i + 1 < argc && ss << argv[i + 1] && ss >> width)
            {
                emulator.SetVideoWidth(width);
            }
            else
                LOG(PROJECT_NAME::Level::Error) << "Setting width from argument failed" << std::endl;
            ++i;
        }
        else if (std::strcmp(argv[i], "-h") == 0 || std::strcmp(argv[i], "--height") == 0)
        {
            int height;
            std::stringstream ss;
            if (i + 1 < argc && ss << argv[i + 1] && ss >> height)
                emulator.SetVideoHeight(height);
            else
                LOG(PROJECT_NAME::Level::Error) << "Setting height from argument failed" << std::endl;
            ++i;
        }
        else if (argv[i][0] != '-')
            path = argv[i];
        else
            std::cerr << "Unrecognized argument: " << argv[i] << std::endl;

    } // end 参数解释

    // 没有必要的游戏文件
    if (path.empty())
    {
        std::cout << "Argument require: ROM path(give me a .nes file)" << std::endl;
        return 1;
    }

    // 模拟器设置keymap,然后启动
    PROJECT_NAME::ParseControllerConf("keybind.conf", p1, p2);
    emulator.SetKeys(p1, p2); // player1 player2
    emulator.Run(path);

    // -------------------------when ok return value
    return 0;
}